package com.chinacreator.galaxylive.utils;


import org.apache.commons.collections.MapUtils;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.jboss.resteasy.specimpl.ResteasyUriBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.*;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.HttpServerErrorException;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import javax.ws.rs.core.UriBuilder;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;


public class RestEampClient {

    private static Logger logger = LoggerFactory.getLogger(RestEampClient.class);
    private static int maxTotalConnections = 300;
    private static int defaultMaxPerRoute = 200;
    private static int socketTimeOut = 6000;
    private static final PoolingHttpClientConnectionManager connectionManager;

    private RestTemplate restTemplate = null;

    static {
        SocketConfig socketConfig = SocketConfig.custom().setTcpNoDelay(true).setSoTimeout(socketTimeOut).build();
        RegistryBuilder<ConnectionSocketFactory> builder = RegistryBuilder.create();
        builder.register("http", PlainConnectionSocketFactory.getSocketFactory());
        try {
            SSLContext sslContext = SSLContext.getInstance("TLSv1");
            TrustManager[] trustAllCerts = {RestEampClient.getX509TrustManager()};
            sslContext.init(null,trustAllCerts, null);
            LayeredConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
            builder.register("https", sslsf);
        } catch (NoSuchAlgorithmException var7) {
            logger.warn("Http连接池SSLConnectionSocketFactory初始化失败，将会无法调用远程https服务，错误原因：", var7);
        } catch (KeyManagementException var8) {
            logger.warn("Http连接池SSLConnectionSocketFactory初始化失败，将会无法调用远程https服务，错误原因：", var8);
        }
        connectionManager = new PoolingHttpClientConnectionManager(builder.build());
        connectionManager.setMaxTotal(maxTotalConnections);
        connectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
        connectionManager.setDefaultSocketConfig(socketConfig);
    }


    private RestEampClient(RestTemplate restTemplate){
        this.restTemplate = restTemplate;
    }

    public static RestEampClient createRestEampClient() {
        RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(10000).setSocketTimeout(10000).setConnectTimeout(5000).build();
        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(connectionManager).setDefaultRequestConfig(requestConfig).build();
        RestTemplate restTemplate = new RestTemplate(new HttpComponentsClientHttpRequestFactory(httpClient));
        return new RestEampClient(restTemplate);
    }

    private String url = null;
    private String[] uriVariables = null;
    private MultiValueMap<String,String> headers = null;

    /**
     * 设置url
     * @param url
     * @param queryParam 使用参数Map<String,Object> 或者 Map<Sting,List<Object>> 或者 Map<Sting,Object[]>
     * @param uriVariables
     * @return
     */
    public RestEampClient url(String url,Map<String,Object> queryParam, String... uriVariables){
        this.uriVariables = uriVariables;
        this.url = url;
        if(MapUtils.isNotEmpty(queryParam)){
            UriBuilder uriBuilder = new ResteasyUriBuilder().uri(url);
            Iterator<Map.Entry<String,Object>> it = queryParam.entrySet().iterator();
            while(it.hasNext()){
                Map.Entry<String,Object> ent = it.next();
                if(ent.getValue() instanceof Object[]){
                    Object[] values = (Object[]) ent.getValue();
                    for(Object temp : values){
                        uriBuilder.queryParam(ent.getKey(),temp);
                    }
                }else if(ent.getValue() instanceof List){
                    List values = (List) ent.getValue();
                    for(Object temp : values){
                        uriBuilder.queryParam(ent.getKey(),temp);
                    }
                }else {
                    uriBuilder.queryParam(ent.getKey(),ent.getValue());
                }
            }
            this.url = uriBuilder.toTemplate();
        }
        return this;
    }

    public RestEampClient header(Map<String, List<String>> headers){
        if(MapUtils.isNotEmpty(headers)){
            if(this.headers == null){
                this.headers = new HttpHeaders();
            }
            this.headers.putAll(headers);
        }
        return this;
    }

    public <T> ResponseEntity<T> get(Class<T> responseType){
        HttpEntity<?> requestEntity = null;
        if(MapUtils.isNotEmpty(headers)){
            requestEntity = new HttpEntity(null,headers);
        }
        return this.exchange(url,HttpMethod.GET,requestEntity,responseType,uriVariables);
    }

    public <T> ResponseEntity<T> post(Object body,Class<T> responseType){
        HttpEntity<?> requestEntity = null;
        if(MapUtils.isNotEmpty(headers)){
            requestEntity = new HttpEntity(body,headers);
        }
        return this.exchange(url,HttpMethod.POST,requestEntity,responseType,uriVariables);
    }

    /**
     *
     * @param url
     * @param method
     * @param requestEntity
     * @param responseType
     * @param uriVariables  @PathParam
     * @param <T>
     * @return
     */
    private <T> ResponseEntity<T> exchange(String url, HttpMethod method, HttpEntity<?> requestEntity,Class<T> responseType, String... uriVariables) {
        ResponseEntity responseEntity = null;
        Long starttime = System.currentTimeMillis();
        try {
            responseEntity = restTemplate.exchange(url, method, requestEntity, responseType, uriVariables);
        }catch (HttpClientErrorException | HttpServerErrorException e){
            responseEntity = new ResponseEntity(e.getResponseBodyAsString(),e.getStatusCode());
        }catch (Exception e){
            String str = ToolUtil.printExceptionDetail(e);
            if(str.length() > 3500){
                str = str.substring(0,3500);
            }
            responseEntity = new ResponseEntity(str, HttpStatus.INTERNAL_SERVER_ERROR);
        }
        return responseEntity;
    }


    /**
     * https 支持
     * @return
     */
    private static X509TrustManager getX509TrustManager(){
        return new X509TrustManager(){
            @Override
            public void checkClientTrusted(X509Certificate[] chain, String authType)
                    throws CertificateException {
            }

            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType)
                    throws CertificateException {
            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
    }



}
